﻿//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
// Exo² samples - Test
// Copyright (C) 2007-2009 Samuel Lacroix and Raphaël Legouge
//
// Distributed under GNU General Public License
// See the License folder of Exo² for details
//
//
// http://www.codeplex.com/exo2 (eng)
//-----------------------------------------------------------------------------


#include "stdafx.h"
#include "tester.h"

 
void IBasicTest::Run()
{
        RunVirtual();
}


tstring IBasicTest::GetName() const
{
        return GetNameVirtual();
} 


const shared_ptr<ITestNotifier>& IBasicTest::GetNotifier() const
{
        return this->pNotifier;
}


// Ajoute un test
void CTester::AddTest(const shared_ptr<IBasicTest>& pTest)
{
        pTest->pNotifier = this->pNotifier;
        this->TestList.push_back(pTest);
}


// Lance le test donné en argument
void CTester::RunTest(const shared_ptr<IBasicTest>& pTest) const
{
        pTest->Run();
}


void CTester::RunAddedTest() const
{                 
        Exo2::CLogger::Instance().Log(_T("CTester : Run all test >Started"));
        const IBasicTest::TList& List = this->TestList;
        size_t TestQuantity = List.size();

        size_t i = 1;
        for (IBasicTest::TList::const_iterator ppTest = List.begin(); ppTest != List.end(); ++ppTest)
        {
                // Création de la phrase d'introduction
                tostringstream oss;
                oss << _T("CTester : test ") << (*ppTest)->GetName() << _T(" (") << i << _T("/") << TestQuantity << _T(") >Started");
                Exo2::CLogger::Instance().Log(oss.str());
                oss.str(_T(""));
                // Lancement du test
                (*ppTest)->Run();
                // Création de la phrase de fin
                oss << _T("CTester : test ") << (*ppTest)->GetName() << _T(" (") << i << _T("/") << TestQuantity << _T(") >Done");
                ++i;
        }
        Exo2::CLogger::Instance().Log(_T("CTester : Run all test >Done"));
}


void ITestNotifier::Notify(const tstring& TestName, int Line, const tstring& Message)
{
        NotifyVirtual(TestName, Line, Message);
}


void CPhysicsTestNotifier::NotifyVirtual(const tstring& TestName, int Line, const tstring& Message)
{
        tostringstream oss;
        oss << TestName << _T(" : Error @ line ") << Line << _T(" (") << Message << _T(")");
        
        Exo2::CLogger::Instance().Log(oss.str());
}


#define NOTIFY_IF_NOT_TRUE(Expr)\
if(!(Expr))\
    this->GetNotifier()->Notify(this->GetName(), __LINE__, _T(#Expr))


void CPhysicsOption::RunVirtual()
{
        //
        // Déroulement : création du moteur, modifications des options, vérification, destruction du moteur
        //
        
        scoped_ptr<Exo2::CPhysicalEngine> pPhysicalEngine;
        pPhysicalEngine.reset(new Exo2::CPhysicalEngine);
        
        {
                bool B;
                
            // Ecriture
                pPhysicalEngine->GetCollisionEngine().SetCollisionProcessing<Exo2::CBasicEntity>(false);
                
            // Vérification
                B = pPhysicalEngine->GetCollisionEngine().GetCollisionProcessing<Exo2::CBasicEntity>();
                NOTIFY_IF_NOT_TRUE(!B);


            // Ecriture
                pPhysicalEngine->GetCollisionEngine().SetCollisionProcessing<Exo2::IBasicParticle>(false);
                
            // Vérification
                B = pPhysicalEngine->GetCollisionEngine().GetCollisionProcessing<Exo2::IBasicParticle>();
                NOTIFY_IF_NOT_TRUE(!B);
                
                
            // Ecriture               
                pPhysicalEngine->GetCollisionEngine().SetCollisionProcessing<Exo2::IBasicRay>(false);
                
            // Vérification
                B = pPhysicalEngine->GetCollisionEngine().GetCollisionProcessing<Exo2::IBasicRay>();
                NOTIFY_IF_NOT_TRUE(!B);
        }
        
        {
                Exo2::EX_float F;
                
                
            // Ecriture
                pPhysicalEngine->SetTimeStep(Exo2::EX_float(0.001));
                
            // Vérification
                F = pPhysicalEngine->GetTimeStep();
                NOTIFY_IF_NOT_TRUE(Core::Utils::IsZero<Exo2::EX_float>(F - 0.001));
        }

        
        {
                size_t S;
                
                
            // Ecriture
                pPhysicalEngine->GetCollisionEngine().SetMaxDepthSphereTreeProcess<Exo2::CBasicEntity>(10);
                
            // Vérification
                S = pPhysicalEngine->GetCollisionEngine().GetMaxDepthSphereTreeProcess<Exo2::CBasicEntity>();
                NOTIFY_IF_NOT_TRUE(S == 10);
                
                
            // Ecriture
                pPhysicalEngine->GetCollisionEngine().SetMaxDepthSphereTreeProcess<Exo2::IBasicParticle>(10);
                
            // Vérification
                S = pPhysicalEngine->GetCollisionEngine().GetMaxDepthSphereTreeProcess<Exo2::IBasicParticle>();
                NOTIFY_IF_NOT_TRUE(S == 10);
                
                
            // Ecriture
                pPhysicalEngine->GetCollisionEngine().SetMaxDepthSphereTreeProcess<Exo2::IBasicRay>(10);
                
            // Vérification
                S = pPhysicalEngine->GetCollisionEngine().GetMaxDepthSphereTreeProcess<Exo2::IBasicRay>();
                NOTIFY_IF_NOT_TRUE(S == 10);
        }
}


void CPhysicsEmitter::RunVirtual()
{
        //
        // Déroulement : Création du moteur, création d'un emetteur de particules, enregistrement dans le moteur,
        // ajout de particules, vérification, retrait de particules, vérification, destruction du moteur
        //

        {
        scoped_ptr<Exo2::CPhysicalEngine> pPhysicalEngine;
        pPhysicalEngine.reset(new Exo2::CPhysicalEngine);
        
        size_t S = 0;
        
    // On dit au moteur que les emetteurs doivent être au maxi
        pPhysicalEngine->GetLimiter().SetFactor(Exo2::EX_float(1.));
        
    // Création de l'emetteur de particules, enregistrement dans le moteur physique
        shared_ptr<Exo2::CBallReset> pBallReset;
        pBallReset.reset(new Exo2::CBallReset(Exo2::MAPI::VECTOR3(0., 0., 0.), 1., 1.));
        shared_ptr<Exo2::CParticleEmitter> pEmitter0;
        pEmitter0.reset(new Exo2::CParticleEmitter(pBallReset, true, true, true, 1., 1., 10, 1000));
        pPhysicalEngine->GetPhysicalObjectManager().Register(pEmitter0);
        
    // Synchronisation
        pPhysicalEngine->GetPhysicalObjectManager().Synchronize();
        pPhysicalEngine->GetLimiter().Synchronize();
                
    // Vérification du nombre de particules
        S = pEmitter0->GetParticleList().size();
        NOTIFY_IF_NOT_TRUE(S == 1000);
        
    // On dit au moteur que les emetteurs doivent être au mini
        pPhysicalEngine->GetLimiter().SetFactor(0.);
        
    // Synchronisation
        pPhysicalEngine->GetPhysicalObjectManager().Synchronize();
        pPhysicalEngine->GetLimiter().Synchronize();
        
    // Vérification du nombre de particules
        S = pEmitter0->GetParticleList().size();
        NOTIFY_IF_NOT_TRUE(S == 10);
        
    // Ajout d'un autre emetteur
        shared_ptr<Exo2::CCylinderReset> pCylinderReset;
        pCylinderReset.reset(new Exo2::CCylinderReset(Exo2::MAPI::VECTOR3(0., 0., 0.), Exo2::MAPI::VECTOR3(1., 0., 0.), 1., 1., 1., 1.));
        shared_ptr<Exo2::CParticleEmitter> pEmitter1;
        pEmitter1.reset(new Exo2::CParticleEmitter(pCylinderReset, true, true, true, 1., 1., 0, 10));
        pPhysicalEngine->GetPhysicalObjectManager().Register(pEmitter1);
        
    // Synchronisation
        pPhysicalEngine->GetPhysicalObjectManager().Synchronize();
        pPhysicalEngine->GetLimiter().Synchronize();
        
    // Vérification du nombre de particules
        S = pEmitter0->GetParticleList().size();
        NOTIFY_IF_NOT_TRUE(S == 10);
        S = pEmitter1->GetParticleList().size();
        NOTIFY_IF_NOT_TRUE(S == 0);
        
    // On dit au moteur que les emetteurs doivent être au maxi
        pPhysicalEngine->GetLimiter().SetFactor(Exo2::EX_float(1.));
        
    // Synchronisation
        pPhysicalEngine->GetPhysicalObjectManager().Synchronize();
        pPhysicalEngine->GetLimiter().Synchronize();

    // Vérification du nombre de particules
        S = pEmitter0->GetParticleList().size();
        NOTIFY_IF_NOT_TRUE(S == 1000);
        S = pEmitter1->GetParticleList().size();
        NOTIFY_IF_NOT_TRUE(S == 10);

        }

        
    // 
    // Test avec les FlashParticles
    //
        {
                scoped_ptr<Exo2::CPhysicalEngine> pPhysicalEngine;
                pPhysicalEngine.reset(new Exo2::CPhysicalEngine);

                size_t S = 0;

                // On dit au moteur que les emetteurs doivent être au maxi
                pPhysicalEngine->GetLimiter().SetFactor(Exo2::EX_float(1.));

                // Création de l'emetteur de particules, enregistrement dans le moteur physique
                shared_ptr<Exo2::CBallReset> pBallReset;
                pBallReset.reset(new Exo2::CBallReset(Exo2::MAPI::VECTOR3(0., 0., 0.), 1., 1.));
                shared_ptr<Exo2::CFlashParticleEmitter> pEmitter0;
                pEmitter0.reset(new Exo2::CFlashParticleEmitter(pBallReset, true, 1., 1., 10, 1000));
                pPhysicalEngine->GetPhysicalObjectManager().Register(pEmitter0);

                // Synchronisation
                pPhysicalEngine->GetPhysicalObjectManager().Synchronize();
                pPhysicalEngine->GetLimiter().Synchronize();

                // Vérification du nombre de particules
                S = pEmitter0->GetParticleList().size();
                NOTIFY_IF_NOT_TRUE(S == 1000);

                // On dit au moteur que les emetteurs doivent être au mini
                pPhysicalEngine->GetLimiter().SetFactor(0.);

                // Synchronisation
                pPhysicalEngine->GetPhysicalObjectManager().Synchronize();
                pPhysicalEngine->GetLimiter().Synchronize();

                // Vérification du nombre de particules
                S = pEmitter0->GetParticleList().size();
                NOTIFY_IF_NOT_TRUE(S == 10);

                // Ajout d'un autre emetteur
                shared_ptr<Exo2::CCylinderReset> pCylinderReset;
                pCylinderReset.reset(new Exo2::CCylinderReset(Exo2::MAPI::VECTOR3(0., 0., 0.), Exo2::MAPI::VECTOR3(1., 0., 0.), 1., 1., 1., 1.));
                shared_ptr<Exo2::CFlashParticleEmitter> pEmitter1;
                pEmitter1.reset(new Exo2::CFlashParticleEmitter(pCylinderReset, true, 1., 1., 0, 10));
                pPhysicalEngine->GetPhysicalObjectManager().Register(pEmitter1);

                // Synchronisation
                pPhysicalEngine->GetPhysicalObjectManager().Synchronize();
                pPhysicalEngine->GetLimiter().Synchronize();

                // Vérification du nombre de particules
                S = pEmitter0->GetParticleList().size();
                NOTIFY_IF_NOT_TRUE(S == 10);
                S = pEmitter1->GetParticleList().size();
                NOTIFY_IF_NOT_TRUE(S == 0);

                // On dit au moteur que les emetteurs doivent être au maxi
                pPhysicalEngine->GetLimiter().SetFactor(Exo2::EX_float(1.));

                // Synchronisation
                pPhysicalEngine->GetPhysicalObjectManager().Synchronize();
                pPhysicalEngine->GetLimiter().Synchronize();

                // Vérification du nombre de particules
                S = pEmitter0->GetParticleList().size();
                NOTIFY_IF_NOT_TRUE(S == 1000);
                S = pEmitter1->GetParticleList().size();
                NOTIFY_IF_NOT_TRUE(S == 10);
        }
        
        //
        // Vérification des emetteur qui ne sont pas en mode loop
        //
        {
                size_t S = 0;
        
                // Création du moteur
                scoped_ptr<Exo2::CPhysicalEngine> pPhysicalEngine;
                pPhysicalEngine.reset(new Exo2::CPhysicalEngine);
                
                // Création et enregistrement des emetteurs
                shared_ptr<Exo2::CCylinderReset> pCylinderReset;
                pCylinderReset.reset(new Exo2::CCylinderReset(Exo2::MAPI::VECTOR3(10., 10., 10.), Exo2::MAPI::VECTOR3(0., 1., 1.), 0.1, 0.5, 0.1, 0.5));
                boost::shared_ptr<Exo2::CFlashParticleEmitter> pEmitter0;
                pEmitter0.reset(new Exo2::CFlashParticleEmitter(pCylinderReset, false, 1., 2., 100, 1000));
                pPhysicalEngine->GetPhysicalObjectManager().Register(pEmitter0);
                
                shared_ptr<Exo2::CDiskReset> pDiskReset;
                pDiskReset.reset(new Exo2::CDiskReset(Exo2::MAPI::VECTOR3(2., 1., 3.), Exo2::MAPI::VECTOR3(1., 0., 0.), 0.1, 0.2));
                boost::shared_ptr<Exo2::CParticleEmitter> pEmitter1;
                pEmitter1.reset(new Exo2::CParticleEmitter(pDiskReset, true, true, true, 0.1, 2., 500, 5000));
                pPhysicalEngine->GetPhysicalObjectManager().Register(pEmitter1);
                                
                // Synchronisation
                pPhysicalEngine->GetPhysicalObjectManager().Synchronize();
                pPhysicalEngine->GetLimiter().Synchronize();
                
                // Vérification du nombre de particules
                S = pEmitter0->GetParticleList().size();
                NOTIFY_IF_NOT_TRUE(S == 1000);
                S = pEmitter1->GetParticleList().size();
                NOTIFY_IF_NOT_TRUE(S == 5000);
                
                // On fait tourner le moteur afin de vider l'emetteur qui n'est pas en loop
                pPhysicalEngine->Work(2.5);
                
                // Vérification du nombre de particules
                S = pEmitter0->GetParticleList().size();
                NOTIFY_IF_NOT_TRUE(S == 0);
                S = pEmitter1->GetParticleList().size();
                NOTIFY_IF_NOT_TRUE(S == 5000);
        }
}


void CPhysicsManagement::RunVirtual()
{
        //
        // Déroulement : Création du moteur, création d'une entité avec le générateur d'objet, enregistrement dans le moteur,
        // création d'une entité, enregistrement dans le moteur, vérification, création de deux particules, enregistrement dans le moteur,
        // vérification, désenregistrement d'une entité, vérification, destruction du moteur
        //

    // Création du moteur
        scoped_ptr<Exo2::CPhysicalEngine> pPhysicalEngine;
        pPhysicalEngine.reset(new Exo2::CPhysicalEngine);
        
    // Création d'une entité avec le générateur
        Exo2::CPhysicalObjectGenerator::IFactoryCallBack::TStrings Param;
        Param.push_back(_T("nom de la fonction"));
        Param.push_back(_T("entity"));
        Param.push_back(_T("data/physics/sphere.exef"));
        Param.push_back(_T("1."));
        Param.push_back(_T("0."));
        Param.push_back(_T("0."));
        Param.push_back(_T("1."));
        Param.push_back(_T("0."));
        Param.push_back(_T("0."));
        Param.push_back(_T("0."));
        shared_ptr<Exo2::IPhysicalObject> pEntity1;
        pEntity1 = pPhysicalEngine->GetPhysicalObjectGenerator().Create(Param);
        
    // Enregistrement de l'entité dans le moteur
        pPhysicalEngine->GetPhysicalObjectManager().Register(pEntity1);
        
    // Création d'une entité
        shared_ptr<Exo2::CExef> pExef;
        pExef = Exo2::CResourceManager::Instance().GetResource<Exo2::CExef>(_T("data/physics/sphere.exef"));
        shared_ptr<Exo2::CEntity> pEntity2;
        pEntity2.reset(new Exo2::CEntity(pExef, 1., Exo2::MAPI::VECTOR3(0., 0., 0.), 0., 0., 0.));
    
    // Enregistrement dans le moteur    
        bool B = pEntity2->IsRegistered();
        NOTIFY_IF_NOT_TRUE(B == false);
        pPhysicalEngine->GetPhysicalObjectManager().Register(pEntity2);
        B = pEntity2->IsRegistered();
        NOTIFY_IF_NOT_TRUE(B == true);
        
        // Pour que le moteur enregistre les objets effectivement, il faut que work soit appelé pour synchroniser le manager
        pPhysicalEngine->Work(0.02);
        
    // Vérification de l'enregistrement
        {
                size_t S;
                
                S = pPhysicalEngine->GetPhysicalObjectManager().GetObjects().size();
                NOTIFY_IF_NOT_TRUE(S == 2);     // 2 entités dans le moteur
                
                S = pPhysicalEngine->GetPhysicalObjectManager().Get(Exo2::CBasicEntity::GetManagementIndexStatic()).size();
                NOTIFY_IF_NOT_TRUE(S == 2);     // 2 entités dans le moteur
                
                NOTIFY_IF_NOT_TRUE(pPhysicalEngine->GetPhysicalObjectManager().Get(Exo2::IBasicParticle::GetManagementIndexStatic()).size() == 0);   // Pas de particule dans le moteur
                
                NOTIFY_IF_NOT_TRUE(pPhysicalEngine->GetPhysicalObjectManager().Get(Exo2::IBasicRay::GetManagementIndexStatic()).size() == 0);        // Pas de rayon dans le moteur
        }
        
    // Création de deux particules
        // Première particule
        shared_ptr<Exo2::CFreeParticle> pParticle1;
        pParticle1.reset(new Exo2::CFreeParticle(true, true, 1., Exo2::MAPI::VECTOR3(0., 0., 0.)));
        // Seconde particule        
        shared_ptr<Exo2::CGhostParticle> pParticle2;
        Exo2::CSmartPosition Position(Exo2::MAPI::VECTOR3(1., 0., 0.));
        pParticle2.reset(new Exo2::CGhostParticle(Position));
        
    // Enregistrement des particules
        pPhysicalEngine->GetPhysicalObjectManager().Register(pParticle1);
        pPhysicalEngine->GetPhysicalObjectManager().Register(pParticle2);
        
        // Pour que le moteur enregistre les objets effectivement, il faut que work soit appelé pour synchroniser le manager
        pPhysicalEngine->Work(0.02);
        
    // Vérification des enregistrements
        {
                size_t S;
                
                S = pPhysicalEngine->GetPhysicalObjectManager().GetObjects().size();
                NOTIFY_IF_NOT_TRUE(S == 4);     // 2 entités dans le moteur et 2 particules
                
                S = pPhysicalEngine->GetPhysicalObjectManager().Get(Exo2::CBasicEntity::GetManagementIndexStatic()).size();
                NOTIFY_IF_NOT_TRUE(S == 2);     // 2 entités dans le moteur
                
                S = pPhysicalEngine->GetPhysicalObjectManager().Get(Exo2::IBasicParticle::GetManagementIndexStatic()).size();
                NOTIFY_IF_NOT_TRUE(S == 2);     // 2 particule dans le moteur
                
                NOTIFY_IF_NOT_TRUE(pPhysicalEngine->GetPhysicalObjectManager().Get(Exo2::IBasicRay::GetManagementIndexStatic()).size()== 0);     // Pas de rayon dans le moteur
        }
        
    // Désenregistrement d'une entité
        pPhysicalEngine->GetPhysicalObjectManager().Unregister(pEntity1);
        
        // Pour que le moteur enregistre les objets effectivement, il faut que work soit appelé pour synchroniser le manager
        pPhysicalEngine->Work(0.02);
        
    // Vérification du désenregistrement
        {
                size_t S;
                
                S = pPhysicalEngine->GetPhysicalObjectManager().GetObjects().size();
                NOTIFY_IF_NOT_TRUE(S == 3);     // 1 entité dans le moteur et 2 particules
                
                S = pPhysicalEngine->GetPhysicalObjectManager().Get(Exo2::CBasicEntity::GetManagementIndexStatic()).size();
                NOTIFY_IF_NOT_TRUE(S == 1);     // 1 entité dans le moteur
                
                S = pPhysicalEngine->GetPhysicalObjectManager().Get(Exo2::IBasicParticle::GetManagementIndexStatic()).size();
                NOTIFY_IF_NOT_TRUE(S == 2);     // 2 particule dans le moteur
                
                NOTIFY_IF_NOT_TRUE(pPhysicalEngine->GetPhysicalObjectManager().Get(Exo2::IBasicRay::GetManagementIndexStatic()).size() == 0);        // Pas de rayon dans le moteur
        }
}


void CPhysicsDispatcher::RunVirtual()
{
        //
        // Déroulement : Création du moteur, modification de deux foncteurs de détections de collision,
        // modification d'un foncteur de résolution de collision, création d'une entité enregistrement dans le moteur,
        // création d'une particule, enregistremnet dans le moteur, simulation d'un tour de boucle, vérification de l'utilisation des foncteurs,
        // modification d'un foncteur de détection de collision, modification d'un foncteur de résolution de collision, création d'une entité,
        // enregistrement dans le moteur, simulation d'un tour de boucle, vérification de l'utilisation des foncteurs
        //
        
        size_t UtilisationDetection = 0;
        size_t UtilisationResolution = 0;
        
    // Création du moteur
        scoped_ptr<Exo2::CPhysicalEngine> pPhysicalEngine;
        pPhysicalEngine.reset(new Exo2::CPhysicalEngine);
        
    // Modification de deux foncteurs de détection de collision
        {
                shared_ptr<Exo2::IDetectionFunctor> pFunctor;
                pFunctor.reset(new CDetectionFunctor(pPhysicalEngine.get(), &UtilisationDetection));

                pPhysicalEngine->GetCollisionEngine().GetCollisionDetectionDispatcher().Add<Exo2::CEntity, Exo2::CWorldEntity>(pFunctor);
                pPhysicalEngine->GetCollisionEngine().GetCollisionDetectionDispatcher().Add<Exo2::CEntity, CCustomFreeParticle>(pFunctor);
        }
        
    // Modification d'un foncteur de résolution de collision        
        {
                shared_ptr<Exo2::ISolvingFunctor> pFunctor;
                pFunctor.reset(new CSolVingFunctor(pPhysicalEngine.get(), &UtilisationResolution));
                
                pPhysicalEngine->GetCollisionEngine().GetCollisionSolvingDispatcher().Add<Exo2::CEntity, CCustomFreeParticle>(pFunctor);
        }
                                                                                       
    // Création d'une entité
        shared_ptr<Exo2::CExef> pExef;
        pExef = Exo2::CResourceManager::Instance().GetResource<Exo2::CExef>(_T("data/physics/sphere.exef"));
        
        shared_ptr<Exo2::CEntity> pEntity;
        pEntity.reset(new Exo2::CEntity(pExef, Exo2::EX_float(1.), Exo2::MAPI::VECTOR3(0., 0., 0.), Exo2::EX_float(0.), Exo2::EX_float(0.), Exo2::EX_float(0.)));
        
    // Enregistrement dans le moteur
        pPhysicalEngine->GetPhysicalObjectManager().Register(pEntity);
                
    // Création d'une particule
        shared_ptr<CCustomFreeParticle> pParticle;
        pParticle.reset(new CCustomFreeParticle);
        
    // Enregistrement dans le moteur
        pPhysicalEngine->GetPhysicalObjectManager().Register(pParticle);
        
    // Simulation d'un tour de boucle
        pPhysicalEngine->Work(Exo2::EX_float(0.02));
        
    // Vérification de l'utilisation des foncteurs
        NOTIFY_IF_NOT_TRUE(UtilisationDetection == 1);
        NOTIFY_IF_NOT_TRUE(UtilisationResolution == 1);
        UtilisationDetection = 0;       // Remise à zéro
        UtilisationResolution = 0;      // Remise à zéro
    
    // Ajout d'un foncteur de détection de collision        
        {
                shared_ptr<Exo2::IDetectionFunctor> pFunctor;
                pFunctor.reset(new CDetectionFunctor(pPhysicalEngine.get(), &UtilisationDetection));
                
                pPhysicalEngine->GetCollisionEngine().GetCollisionDetectionDispatcher().Add<Exo2::CWorldEntity, CCustomFreeParticle>(pFunctor);
        }
        
    // Ajout d'un foncteur de résolution de collision
        {
                shared_ptr<Exo2::ISolvingFunctor> pFunctor;
                pFunctor.reset(new CSolVingFunctor(pPhysicalEngine.get(), &UtilisationResolution));
                
                pPhysicalEngine->GetCollisionEngine().GetCollisionSolvingDispatcher().Add<Exo2::CWorldEntity, CCustomFreeParticle>(pFunctor);
        }
        
    // Création d'un entité
        shared_ptr<Exo2::CWorldEntity> pWorldEntity;
        pWorldEntity.reset(new Exo2::CWorldEntity(pExef, Exo2::EX_float(1.), Exo2::MAPI::VECTOR3(0., 0., 0.), 0., 0., 0.));
        
    // Enregistrement dans le moteur
        pPhysicalEngine->GetPhysicalObjectManager().Register(pWorldEntity);
        
    // Simulation d'un tour de boucle
        pPhysicalEngine->Work(Exo2::EX_float(0.02));
                                     
    // Vérification de l'utilisation des foncteurs
        NOTIFY_IF_NOT_TRUE(UtilisationDetection == 3);
        NOTIFY_IF_NOT_TRUE(UtilisationResolution == 2);
        UtilisationDetection = 0;       // Remise à zéro
        UtilisationResolution = 0;      // Remise à zéro
}


void CPhysicsDispatcher::CDetectionFunctor::Run(const shared_ptr<Exo2::IPhysicalObject>& pObject1, const shared_ptr<Exo2::IPhysicalObject>& pObject2, Exo2::CCollisionDetectionDispatcher::TCollisions* pCollisionList)
{
        ++(*this->pSensor);
        Exo2::CBasicCollision Collision;
        Collision.Depth = Exo2::EX_float(1.);
        Collision.Normal = Exo2::MAPI::VECTOR3(1., 0., 0.);
        Collision.Position = Exo2::MAPI::VECTOR3(1., 1., 1.);
        Collision.pObject1 = pObject1.get();
        Collision.pObject2 = pObject2.get();
        Collision.pSphere1 = NULL;
        Collision.pSphere2 = NULL;
        pCollisionList->push_front(Collision);
}


void CPhysicsDispatcher::CSolVingFunctor::Run(const Exo2::CBasicCollision& /*Collision*/)
{
        ++(*this->pSensor);
}

#undef NOTIFY_IF_NOT_TRUE